﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Messaging;
using System.ServiceModel;
using System.Reflection;

namespace yule.Common.WCF
{
    /// <summary>
    /// 服务代理
    /// 参考:http://www.cnblogs.com/artech/archive/2010/01/08/1642607.html
    /// </summary>
    internal sealed class ServiceRealProxy<T> : System.Runtime.Remoting.Proxies.RealProxy where T : class
    {
        private string _endpointName;

        public ServiceRealProxy(string endpointName)
            : base(typeof(T))
        {
            if (string.IsNullOrEmpty(endpointName))
            {
                throw new ArgumentNullException("endpointName");
            }
            this._endpointName = endpointName;
        }


        public override System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)
        {
            T channel = yule.Common.ServiceManager.ServiceContext.GetFactory<T>(this._endpointName).CreateChannel();
            IMethodCallMessage methodCall = (IMethodCallMessage)msg;
            IMethodReturnMessage methodReturn = null;
            object[] copiedArgs = Array.CreateInstance(typeof(object), methodCall.Args.Length) as object[];
            methodCall.Args.CopyTo(copiedArgs, 0);
            try
            {
                object returnValue = methodCall.MethodBase.Invoke(channel, copiedArgs);
                methodReturn = new ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall);
                (channel as ICommunicationObject).Close();
            }
            catch (ServiceActivationException ex)
            {
                (channel as ICommunicationObject).Close();
                throw ex;
            }
            catch (TargetInvocationException ex2)
            {
                try
                {
                    FaultException<yule.Common.WCF.ServiceException> fault = ex2.InnerException as FaultException<yule.Common.WCF.ServiceException>;
#warning 异常信息描述还不够完全
                    Exception ex = new Exception(fault.Detail.MethodName + ":" + fault.Detail.Message);
                    methodReturn = new ReturnMessage(ex, methodCall);
                }
                catch
                {
                    throw ex2;
                }
                finally
                {
                    (channel as ICommunicationObject).Abort();
                }
            }
            catch (Exception ex3)
            {
                if (ex3.InnerException != null)
                {
                    methodReturn = new ReturnMessage(ex3.InnerException, methodCall);
                }
                else
                {
                    methodReturn = new ReturnMessage(ex3, methodCall);
                }
                (channel as ICommunicationObject).Close();
            }
            return methodReturn;
        }

    }
}